Caching de Fragmentos
=====================

Caching de fragmentos refere-se ao ato de armazenar em cache apenas um 
fragmento de uma página. Por exemplo, se uma página exibe em uma tabela o 
resumo anual de vendas, podemos armazenar essa tabela em cache para eliminar 
o tempo necessário para gera-la em cada requisição.

Para utilizar o caching de fragmentos, utilizamos os métodos 
[CController::beginCache()|CBaseController::beginCache()] e
[CController::endCache()|CBaseController::endCache()] na visão de um controle. 
Esses dois métodos marcam, respectivamente, o início e termino do conteúdo da 
página que deve ser armazenado em cache. Assim como no [caching de dados](/doc/guide/caching.data), 
precisamos de um ID para identificar o fragmento armazenado.

~~~
[php]
...outro conteúdo HTML...
<?php if($this->beginCache($id)) { ?>
...conteúdo que deve ser armazenado...
<?php $this->endCache(); } ?>
...outro conteúdo HTML...
~~~

No código acima, se o método [beginCache()|CBaseController::beginCache()] retornar 
false, o conteúdo já armazenado no cache será exibido, caso contrário, o conteúdo 
dentro do `if` será executado e, então, armazenado quando o método 
[endCache()|CBaseController::endCache()] for executado. Na realidade, os métodos 
[beginCache()|CBaseController::beginCache()] e
[endCache()|CBaseController::endCache()] encapsulam os métodos de mesmo nome existentes 
no widget [COutputCache]. Sendo assim, as opções de caching podem ser os valores 
iniciais para qualquer uma das propriedades de [COutputCache].

### Duração

Provavelmente a opção mais utilizada seja a [duration|COutputCache::duration], que 
especifica por quanto tempo o conteúdo deve ser mantido válido no cache. Seu 
funcionamento é similar ao parâmetro de tempo de expiração do método [CCache::set()]. 
O código a seguir armazena em cache o fragmento por, no máximo, uma hora:

~~~
[php]
...outro conteúdo HTML...
<?php if($this->beginCache($id, array('duration'=>3600))) { ?>
...conteúdo a ser armazenado...
<?php $this->endCache(); } ?>
...outro conteúdo HTML...
~~~

Se não informamos a duração, seu valor padrão será 60, indicando que o conteúdo 
do cache deve ser invalidado depois de 60 segundos.

### Dependência

Assim com o [caching de dados](/doc/guide/caching.data), fragmentos de conteúdo 
armazenados em cache também podem ter dependências. Por exemplo, o conteúdo de um 
post pode se exibido, caso ele tenha sido alterado ou não.

Pada especificar uma dependência, devemos utilizar a opção [dependency|COutputCache::dependency], 
que pode ser um objeto implementando a interface [ICacheDependency] ou um 
vetor de configuração que pode ser utilizado para gerar a dependência. O código 
a seguir especifica que o fragmento depende da alteração do valor da coluna `lastModified`:

~~~
[php]
...outro conteúdo HTML...
<?php if($this->beginCache($id, array('dependency'=>array(
		'class'=>'system.caching.dependencies.CDbCacheDependency',
		'sql'=>'SELECT MAX(lastModified) FROM Post')))) { ?>
...conteúdo a ser armazenado no cache...
<?php $this->endCache(); } ?>
...outro conteúdo HTML...
~~~

### Variação

O conteúdo armazenado em cache pode sofrer variações de acordo com alguns parâmetros. 
Por exemplo, o perfil pessoal pode ter aparências diferentes para diferentes usuários. 
Para armazenar em cache o conteúdo do perfil, seria interessante que a cópia em cache 
varie de acordo com os IDs dos usuários. Isso significa que devemos utilizar IDs 
diferentes ao chamar o método [beginCache()|CBaseController::beginCache()].

Em vez de deixar para os desenvolvedores o controle sobre a variação desses IDs, 
a classe [COutputCache] já possui esse recurso. Abaixo, um resumo:

   - [varyByRoute|COutputCache::varyByRoute]: mudando seu valor para true, o 
conteúdo em cache irá variar de acordo com a [rota](/doc/guide/basics.controller#route). 
Dessa forma, cada combinação de controle/ação terá seu conteúdo armazenado em cache 
separadamente.

   - [varyBySelection|COutputCache::varyBySession]: mudando seu valor para true, 
podemos fazer com que o conteúdo em cache varie de acordo com os IDs da sessão. 
Dessa forma, cada sessão de usuário pode ter conteúdos diferentes e todos servidos 
através do cache.

   - [varyByParam|COutputCache::varyByParam]: ao atribuir um vetor de nomes 
a essa opção, podemos fazer com que o conteúdo do cache varie de acordo com 
valores passados através de GET. Por exemplo, se uma página exibe o conteúdo de um 
post de acordo com a variável GET `id`, podemos definir [varyByParam|COutputCache::varyByParam] 
como `array('id')`, assim podemos armazenar em cache o conteúdo de cada post. 
Sem esse tipo de variação, poderiamos apenas armazenar um único post.

   - [varyByExpression|COutputCache::varyByExpression]: ao atribuir uma expressão 
PHP a essa opção, podemos fazer com que o conteúdo do cache varie de acordo 
com o resultado dessa expressão. Essa opção está disponível a partir da versão 1.0.4.


### Tipos de Requisição

As vezes, queremos que o cache de fragmentos esteja habilitado somente para 
certos tipos de requisições. Por exemplo, para uma página exibindo um formulário, 
queremos armazenar o formulário apenas na primeira vez em que a página é requisitada 
(via GET). Nas exibições seguintes (via POST), o formulário não deve ser armazenado 
porque ele pode conter os dados informados pelos usuários. Para isso, podemos 
utilizar a opção [requestTypes|COutputCache::requestTypes]:

~~~
[php]
...outro conteúdo HTML...
<?php if($this->beginCache($id, array('requestTypes'=>array('GET')))) { ?>
...conteúdo a ser armazenado...
<?php $this->endCache(); } ?>
...outro conteúdo armazenado...
~~~

Caching Aninhado
----------------

O caching de fragmentos pode ser aninhado. Isso é, um fragmento em cache 
que está dentro de um outro fragmento, também em cache. Por exemplo, os 
comentários estão em cache, junto do conteúdo do post que também está em cache.

~~~
[php]
...outro conteúdo HTML...
<?php if($this->beginCache($id1)) { ?>
...conteúdo externo em cache...
	<?php if($this->beginCache($id2)) { ?>
	...conteúdo interno em cache...
	<?php $this->endCache(); } ?>
...conteúdo externo em cache...
<?php $this->endCache(); } ?>
...outro conteúdo em cache...
~~~

Diferentes opções de caching podem ser utilizadas para os caches aninhados. 
Por exemplo, os caches interno e o externo, no exemplo acima, podem ter durações 
diferentes. Quando os dados armazenados em cache do conteúdo externo tornarem-se
inválidos, o cache do conteúdo interno ainda vai conter seu fragmento válido. Entretanto, o 
inverso não é verdadeiro. Se o conteúdo externo contém dados válidos, ele sempre 
irá fornecer a cópia em cache, mesmo que o cache do conteúdo interno já tenha 
expirado.
Você deve ter cuidado na definição das durações ou as dependências dos caches aninhados,
caso contrário, os fragmentos desatualizados internas podem ser mantidos no fragmento exterior.

<div class="revision">$Id$</div>
